package org.jetlinks.pro.things;

import org.jetlinks.core.message.ThingMessage;
import org.jetlinks.core.things.MetadataId;
import org.jetlinks.core.things.ThingId;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;

import java.util.function.Function;

/**
 * 物连接器,用于连接物的物模型数据进行处理
 *
 * @see org.jetlinks.core.things.ThingRpcSupport
 * @see org.jetlinks.pro.things.impl.connector.AbstractThingsConnector
 * @since 1.12
 */
public interface ThingsConnector extends Disposable {

    /**
     * 连接到指定物的物模型,当产生消息时,handler将被调用.可调用返回值的{@link Disposable#dispose()}来断开连接
     *
     * @param thingId    物ID
     * @param metadataId 物模型ID
     * @param handler    消息处理器
     * @return Disposable
     */
    Disposable connectTo(ThingId thingId,
                         MetadataId metadataId,
                         Function<ThingMessage, Mono<Void>> handler);

    /**
     * 连接到当前物的物模型.物实例ID由数据源生成. 通常用于批量连接处理,比如在物模版里配置规则,计算对应物实例
     * 当产生消息时,handler将被调用.可调用返回值的{@link Disposable#dispose()}来断开连接
     *
     * @param metadataId 物模型ID
     * @param handler    消息处理器
     * @return Disposable
     */
    default Disposable connectTo(MetadataId metadataId,
                                 Function<ThingMessage, Mono<Void>> handler) {
        return () -> {
        };
    }

    /**
     * 监听断开连接,并执行自定义动作
     *
     * @param action 自定义动作
     */
    default void doOnDispose(Disposable action) {
        if (isDisposed()) {
            action.dispose();
        }
    }

    /**
     * 判断是否包装自指定的类型,通常在将当前接口转为特定的类型时进行判断.
     *
     * @param target 目标类型
     * @return true or false
     */
    default boolean isWrapperFor(Class<?> target) {
        return target.isInstance(this);
    }

    /**
     * 将当前接口拆包为指定的类型
     *
     * @param target 目标类型
     * @return 指定的类型
     * @throws ClassCastException 当无法转为指定类型时抛出
     */
    default <T> T unwrap(Class<T> target) throws ClassCastException {
        return target.cast(this);
    }

}
